package models

import (
	"3rd/mongo"
	"time"
	goerrors "github.com/go-errors/errors"
	"github.com/jinzhu/now"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type PointData struct {
	Ts  int64   `json:"ts"`
	Val float64 `json:"val"`
}
type DataFormat struct {
	ID   int64
	Ts   int64
	Vals []PointData
	Mean float64
}

type DataAlert struct {
	ID   int64
	Ts   int64
	Msg string
	Val float64
}

func GetData1Min(id, begin, end int64, rst *[]PointData) (err error) {
	bt := time.Unix(begin, 0)
	et := time.Unix(end, 0)
	newB := now.New(bt).BeginningOfHour().Unix()
	newE := now.New(et).EndOfHour().Unix()
	Log.Debug("begin:%v->new begin:%v, end:%v->new end:%v", begin, newB, end, newE)

	err = mongo.DO(db_data, col_hour, func(c *mgo.Collection) (err error) {
		var data []DataFormat

		if err = c.Find(bson.M{"id": id, "ts": bson.M{"$gte": newB, "$lte": newE}}).Sort("ts").All(&data); err != nil {
			return goerrors.New(err)
		}
		for _, v := range data {
			if v.Ts < begin {
				idx := -1
				for i, val := range v.Vals {
					if val.Ts >= begin {
						idx = i
						Log.Debug("val.Ts:%v >= begin", val.Ts)
						break
					}
				}
				if idx >= 0 {
					*rst = append(*rst, v.Vals[idx:]...)
				}
			} else if v.Ts >= begin && v.Ts < now.New(et).BeginningOfHour().Unix() {
				*rst = append(*rst, v.Vals[:]...)
			} else if v.Ts >= now.New(et).BeginningOfHour().Unix() {
				idx := -1
				for i, val := range v.Vals {
					if val.Ts >= end {
						Log.Debug("val.Ts:%v >= end", val.Ts)
						idx = i
						break
					}
				}
				if idx >= 0 {
					*rst = append(*rst, v.Vals[:idx]...)
				}
			}
		}
		return nil
	})
	beginOfHour := now.BeginningOfHour().Unix()
	if end > beginOfHour {
		err = mongo.DO(db_data, col_minute, func(c *mgo.Collection) (err error) {
			var data []PointData
			if err = c.Find(bson.M{"id": id, "ts": bson.M{"$gte": beginOfHour, "$lte": end}}).Sort("ts").All(&data); err != nil {

			} else {
				*rst = append(*rst, data[:]...)
			}
			return err
		})
	}
	return err
}

func GetData1H(id, begin, end int64, rst *[]PointData) (err error) {
	return mongo.DO(db_data, col_hour, func(c *mgo.Collection) (err error) {
		var data []DataFormat
		if err := c.Find(bson.M{"id": id, "ts": bson.M{"$gte": begin, "$lte": end}}).Select(
			bson.M{"_id": 0, "ts": 1, "mean": 1}).All(&data); err != nil {
			return goerrors.New(err)
		}
		for _, v := range data {
			*rst = append(*rst, PointData{Ts: v.Ts, Val: v.Mean})
		}

		return nil
	})
}

func GetData1D(id, begin, end int64, rst *[]PointData) (err error) {
	return mongo.DO(db_data, col_day, func(c *mgo.Collection) (err error) {
		var data []DataFormat
		if err := c.Find(bson.M{"id": id, "ts": bson.M{"$gte": begin, "$lte": end}}).Select(
			bson.M{"_id": 0, "ts": 1, "mean": 1}).All(&data); err != nil {
			return goerrors.New(err)
		}
		for _, v := range data {
			*rst = append(*rst, PointData{Ts: v.Ts, Val: v.Mean})
		}
		if len(data) < 1 {
			return GetData1H(id, begin, end, rst)
		}

		return nil
	})
}

func GetData1Mon(id, begin, end int64, rst *[]PointData) (err error) {
	return mongo.DO(db_data, col_month, func(c *mgo.Collection) (err error) {
		var data []DataFormat
		if err := c.Find(bson.M{"id": id, "ts": bson.M{"$gte": begin, "$lte": end}}).Select(
			bson.M{"_id": 0, "ts": 1, "mean": 1}).All(&data); err != nil {
			return goerrors.New(err)
		}
		for _, v := range data {
			*rst = append(*rst, PointData{Ts: v.Ts, Val: v.Mean})
		}
		if len(data) < 1 {
			return GetData1D(id, begin, end, rst)
		}

		return nil
	})
}

func GetData(id, begin, end int64, step string, data *[]PointData) (err error) {
	switch step {
	case "M":
		return GetData1Mon(id, begin, end, data)
	case "d":
		return GetData1D(id, begin, end, data)
	case "h":
		return GetData1H(id, begin, end, data)
	case "m":
		return GetData1Min(id, begin, end, data)
	default:
		return goerrors.New("Unknown step value")
	}
	return nil
}


func GetTroubleData(begin, end int64, count int, data *[]DataAlert) (err error) {
	return mongo.DO(db_data, "alert", func(c *mgo.Collection) (err error) {
		var data []DataFormat
		if err := c.Find(bson.M{"ts": bson.M{"$gte": begin, "$lte": end}}).Select(
			bson.M{"_id": 0}).Limit(count).All(&data); err != nil {
			return goerrors.New(err)
		}

		return nil
	})
}
